/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.yonsei.iwb.sdt;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.vocabulary.RDF;
import java.util.Vector;
import org.yonsei.iwb.sdt.algorithm.DCSSearcher;
import org.yonsei.iwb.sdt.algorithm.TreeDecomposer;
import org.yonsei.iwb.sdt.datastructure.DecomposeCandidateSet;
import org.yonsei.iwb.sdt.datastructure.tree.DEdge;
import org.yonsei.iwb.sdt.datastructure.tree.DNode;
import org.yonsei.iwb.sdt.datastructure.rule.DecisionRule;
import org.yonsei.iwb.sdt.datastructure.tree.NodeType;
import org.yonsei.iwb.sdt.datastructure.TargetInstanceSet;
import org.yonsei.iwb.sdt.datastructure.rule.DecisionRuleSet;
import org.yonsei.iwb.sdt.datastructure.rule.DecisionRuleComponent;
import org.yonsei.iwb.sdt.ontology.ClassModel;
import org.yonsei.iwb.sdt.ontology.OntologyModel;
import org.yonsei.iwb.sdt.ontology.PropertyArc;
import org.yonsei.iwb.sdt.ontology.UncountedResources;
import org.yonsei.iwb.sdt.util.SDTLog;

/**
 *
 * @author JDK
 */
public class SDTLearner {

    private Resource targetClass;
    public static Property TARGETPROPERTY;
    private Vector<String> targetInstances;
    private int learningOption;
    private Model model;
    private ClassModel classmodel;
    private TargetInstanceSet targetinstSet;
    private Vector<Resource> instanceSet;
    private DNode root;
    private DecomposeCandidateSet dcs;
    private DecisionRuleSet ners;
    private UncountedResources ur;
    public static int NODE_ID = 0;
    public static int TARGETVALUESIZE = 2;
    public static int EXPAND_DEPTH = 1;
    public static int PRESENT_DEPTH = 0;
    private double ENTROPY_THRESHOLD = 0;

    public SDTLearner(String targetClass, String targetProperty, OntologyModel ontmodel, int learningOption) {
        this.model = ontmodel.getJenaModel();
        this.learningOption = learningOption;
        this.targetClass = this.model.getResource(targetClass);
        this.classmodel = new ClassModel();
        this.ners = new DecisionRuleSet();
        SDTLearner.TARGETPROPERTY = model.getProperty(targetProperty);        

        Vector<RDFNode> valueSet = new Vector<RDFNode>();
//        TargetInstanceValueSet tivs = new TargetInstanceValueSet();
        this.targetinstSet = new TargetInstanceSet();
        
        ResIterator res = this.model.listResourcesWithProperty(RDF.type, this.targetClass);
        while (res.hasNext()) {               
            Resource instance = res.nextResource();                        
            NodeIterator ni = this.model.listObjectsOfProperty(instance, SDTLearner.TARGETPROPERTY);
            while (ni.hasNext()) {
                RDFNode value = ni.nextNode();
                if (!valueSet.contains(value)) {
                    valueSet.add(value);
                }
                this.targetinstSet.put(instance, valueSet.indexOf(value));
            }
        }

        SDTLearner.TARGETVALUESIZE = valueSet.size();
        this.targetinstSet.setTargetInstanceValueSet(valueSet);
        this.targetinstSet.printTargetInstanceSet();

        this.instanceSet = this.targetinstSet.getInstance();
        this.root = new DNode(this.instanceSet, "Root");
//        this.targetinstSet.printTargetInstanceSet();
        this.ur = new UncountedResources();
    }

    @Deprecated
    public SDTLearner(String targetClass, Vector<Resource> positiveInstance, Vector<Resource> negativeInstance, OntologyModel ontmodel, int learningOption) {

        this.model = ontmodel.getJenaModel();
        this.learningOption = learningOption;
        this.targetClass = model.getResource(targetClass);
        this.classmodel = new ClassModel();
        this.classmodel.classModelMaker(model);
        this.ners = new DecisionRuleSet();
        this.targetinstSet = new TargetInstanceSet(positiveInstance, negativeInstance);
        this.instanceSet = this.targetinstSet.getInstance();
        this.root = new DNode(this.instanceSet, "Root");
        this.ur = new UncountedResources();

    }

    public SDTLearner(Vector<Resource> positiveInstance, Vector<Resource> negativeInstance, OntologyModel ontmodel, int learningOption) {
        this.model = ontmodel.getJenaModel();
        this.learningOption = learningOption;
        this.classmodel = new ClassModel();
        this.classmodel.classModelMaker(model);
        this.ners = new DecisionRuleSet();
        this.targetinstSet = new TargetInstanceSet(positiveInstance, negativeInstance);
        this.instanceSet = this.targetinstSet.getInstance();
        this.root = new DNode(this.instanceSet, "Root");
        this.ur = new UncountedResources();
    }

    public DNode learningStart(boolean nontargetclass) {

        dcs = new DecomposeCandidateSet();
        DCSSearcher sdcs = new DCSSearcher(this.model, this.classmodel, this.learningOption);
        TreeDecomposer td = new TreeDecomposer(this.model, this.classmodel, this.learningOption, this.targetinstSet, this.ENTROPY_THRESHOLD);

        long startTime = System.currentTimeMillis();

        sdcs.searchDecomposeCandidateSet(dcs, this.instanceSet, new Vector<PropertyArc>());
        this.root.setTargetValueInstanceInformation(targetinstSet);
        this.root.setEntropy();

        td.decomposeTreeNode(this.root, dcs);

        long endTime = System.currentTimeMillis();
        System.out.println("\nRunning Time = " + (endTime - startTime) / 1000.0f + " sec");
        td.setinit();
//        dcs.printDecomposeCandidateSet();

        SDTLog.log(SDTLog.BASIC, root.toString());
        this.printNode(this.root);

//        SDTSearcher sdts = new SDTSearcher(this.model);
//        DecisionRuleSet drs = this.getDecisionRuleSet();
//        
//        for (int i = 0; i < drs.size(); i++) {
//            System.out.println("-----------------------------------------------------------------------");
//            DecisionRule dr = drs.get(i);            
//            Vector<Resource> resultset = sdts.getRuleMatcherInstanceSet(dr, new Vector<Resource>());
//            
//        }

        return this.root;
    }

    public DNode learningStart() {
        dcs = new DecomposeCandidateSet();
        DCSSearcher sdcs = new DCSSearcher(this.model, this.classmodel, this.learningOption);
        TreeDecomposer td = new TreeDecomposer(this.model, this.classmodel, this.learningOption, this.targetinstSet, this.ENTROPY_THRESHOLD);

        long startTime = System.currentTimeMillis();
        dcs.setTargetclass(targetClass);
        sdcs.searchDecomposeCandidateSet(dcs, this.instanceSet, new Vector<PropertyArc>());
        this.root.setTargetValueInstanceInformation(targetinstSet);
        this.root.setEntropy();
        td.decomposeTreeNode(this.root, dcs);
        long endTime = System.currentTimeMillis();
        System.out.println("\nRunning Time = " + (endTime - startTime) / 1000.0f + " sec");
        
        SDTLog.log(SDTLog.DETAIL, root.toString());
        this.printNode(this.root);

//        SDTSearcher sdts = new SDTSearcher(this.model);
//        DecisionRuleSet drs = this.getDecisionRuleSet();
////        
//        for (int i = 0; i < drs.size(); i++) {
//            System.out.println("-----------------------------------------------------------------------");            
//            DecisionRule dr = drs.get(i);            
//            System.out.println(dr.toString());
//            Vector<Resource> resultset = sdts.getRuleMatcherInstanceSet(dr, new Vector<Resource>());
//            System.out.println("--- " + resultset.size());
//        }

//        GraphVizTest gv = new GraphVizTest();
//        gv.showTree(node);

        return this.root;
    }

    public void setENTROPY_THRESHOLD(double d) {
        this.ENTROPY_THRESHOLD = d;
    }

    public DecisionRuleSet getDecisionRuleSet() {
        if (this.ners.isEmpty()) {
            generateDecisionRuleSet(this.root, new DecisionRule());
        }
        return this.ners;
    }

    private void generateDecisionRuleSet(DNode node, DecisionRule olddr) {
        for (int i = 0; i < node.getEdge().size(); i++) {
            DEdge edge = node.getEdge().get(i);
            DecisionRuleComponent drc = new DecisionRuleComponent(edge.getRefinement());
            DecisionRule newdr = new DecisionRule(olddr, drc);
            this.ners.add(newdr);
            if (edge.getChildNode().NODE_TYPE == NodeType.BRANCHNODE) {
                generateDecisionRuleSet(edge.getChildNode(), newdr);
            }
        }
    }

    public void setLearningOption(int option) {
        this.learningOption = option;
    }

    public void printNode(DNode node) {
//        String s = new String();        
        for (int i = 0; i < node.getEdge().size(); i++) {
            DEdge edge = node.getEdge().get(i);

            SDTLog.log(SDTLog.BASIC, edge.toString());

//            edge.getChildNode().setRuleComposer(node.getRuleComposer(), edge.getRefinement());  // rule generate

            if (edge.getChildNode().NODE_TYPE == NodeType.BRANCHNODE) {
                SDTLog.log(SDTLog.BASIC, edge.getChildNode().toString());
                printNode(edge.getChildNode());
            } else {
                SDTLog.log(SDTLog.BASIC, edge.getChildNode().toString());
            }
        }
    }
}
